package com.jtbd.exceptions;

import com.jtbd.constants.ResponseCodeEnum;
import com.jtbd.dto.result.ResponseBaseData;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.MessageSourceResolvable;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.HandlerMethodValidationException;

import java.sql.SQLException;
import java.sql.SQLIntegrityConstraintViolationException;
import java.util.Date;
import java.util.Objects;
import java.util.Properties;

@Slf4j
@RestControllerAdvice
public class GlobalException {
    private void logException(Exception e) {
        log.error("GlobalException==Error:{}", e.getMessage());
    }

    @ExceptionHandler(SystemException.class)
    protected ResponseBaseData<String> handleException(SystemException e) {
        logException(e);
        return ResponseBaseData.error(ResponseCodeEnum.ERROR.getCode(), e.getMessage());
    }

    @ExceptionHandler({MethodArgumentNotValidException.class, HandlerMethodValidationException.class})
    protected ResponseBaseData<String> handleValidationExceptions(Exception e) {
        String errorMessage;

        if (e instanceof MethodArgumentNotValidException validException) {
            // 处理请求体参数验证异常
            errorMessage = validException.getBindingResult().getFieldError() != null
                    ? validException.getBindingResult().getFieldError().getDefaultMessage()
                    : "请求参数验证失败";
        } else if (e instanceof HandlerMethodValidationException handlerException) {
            // 处理路径参数/请求参数验证异常（Spring 5.3+）
            errorMessage = handlerException.getAllValidationResults().stream()
                    .flatMap(result -> result.getResolvableErrors().stream())
                    .findFirst()
                    .map(MessageSourceResolvable::getDefaultMessage)
                    .orElse("请求参数验证失败");
        } else {
            // 理论上不会走到这里，因为@ExceptionHandler已限定异常类型
            errorMessage = "参数验证异常";
        }
        return ResponseBaseData.error(ResponseCodeEnum.ERROR.getCode(), errorMessage);
    }

    /**
     * 处理BadCredentialsException异常
     * 当用户身份验证失败时调用此方法返回错误响应
     *
     * @param e BadCredentialsException异常对象
     * @return 包含错误信息的响应数据对象
     */
    @ExceptionHandler(BadCredentialsException.class)
    protected ResponseBaseData<String> handleException(BadCredentialsException e) {
        // 记录异常日志
        logException(e);

        return ResponseBaseData.error(ResponseCodeEnum.ERROR.getCode(), "用户身份无效！");
    }

    /**
     * 处理数据访问异常
     *
     * @param e DataAccessException异常对象
     * @return 包含错误信息的响应数据
     */
    @ExceptionHandler(DataAccessException.class)
    protected ResponseBaseData<String> handleException(DataAccessException e) {
        logException(e);
        // 处理重复键异常
        if (e instanceof DuplicateKeyException) {
            return ResponseBaseData.error(ResponseCodeEnum.ERROR.getCode(), "数据已存在");
        }
        return ResponseBaseData.error(ResponseCodeEnum.ERROR.getCode(), "数据操作失败");
    }

    /**
     * 处理认证异常
     *
     * @param e AuthenticationException异常对象
     * @return 包含错误信息的响应数据
     */
    @ExceptionHandler(AuthenticationException.class)
    protected ResponseBaseData<String> handleException(AuthenticationException e) {
        logException(e);
        return ResponseBaseData.error(ResponseCodeEnum.ERROR.getCode(), e.getMessage());
    }

    /**
     * 处理通用异常
     *
     * @param e Exception异常对象
     * @return 包含错误信息的响应数据
     */
    @ExceptionHandler(Exception.class)
    protected ResponseBaseData<String> handleException(Exception e) {
        logException(e);
        return ResponseBaseData.error(ResponseCodeEnum.ERROR);
    }

}
